package com.swak.reactivex.transport.codec;

import java.util.List;

import com.swak.reactivex.transport.Channel;
import com.swak.reactivex.transport.Codec;
import com.swak.reactivex.transport.NettyCodec;
import com.swak.reactivex.transport.exception.CodecException;
import com.swak.reactivex.transport.exception.ExchangeException.ExchangeMethod;
import com.swak.registry.URL;
import com.swak.spi.ExtensionLoader;
import com.swak.utils.Lists;

import io.netty.buffer.ByteBuf;

/**
 * 支持 - 多种协议
 * 
 * @author 618lf
 */
public class MultipleCodec implements Codec {

	private static ExtensionLoader<Codec> CodecLoader = ExtensionLoader.getExtensionLoader(Codec.class);
	private static final Class<?>[] CodecArgs = new Class<?>[] { URL.class };

	private final List<Codec> codecs = Lists.newArrayList();

	public MultipleCodec(URL url) {
		List<Codec> codecs = CodecLoader.loadAll(CodecArgs, new Object[] { url }, Codec.class.getClassLoader());
		this.codecs.addAll(codecs);
	}

	@Override
	public void encode(Channel channel, ByteBuf buffer, Object message) throws CodecException {
		if (message == null) {
			return;
		}

		boolean hasSupportCodec = false;
		for (Codec codec : codecs) {
			if (codec.support(message)) {
				codec.encode(channel, buffer, message);
				hasSupportCodec = true;
				break;
			}
		}

		// 是否有支持的编码器
		if (!hasSupportCodec) {
			throw new CodecException(ExchangeMethod.Write, message, "缺少针对 " + message.getClass().getName() + " 类型的编码器");
		}
	}

	@Override
	public Object decode(Channel channel, ByteBuf buffer) throws CodecException {

		// 尝试解析, 通过魔数判断是否可以解析
		for (Codec codec : codecs) {
			Object result = codec.decode(channel, buffer);
			if (result != NettyCodec.DecodeResult.CHECK_MAGIC_ERROR) {
				return result;
			}
		}

		// 如果都不能解析，则跳过
		return NettyCodec.DecodeResult.SKIP_SOME_INPUT;
	}
}